﻿using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using GMusicBox.Core;
using GMusicBox.Core.Setting;

namespace GMusicBox
{
    public partial class frmDesktopLyric : PerPixelAlphaBlendForm
    {
        public frmDesktopLyric()
        {
            InitializeComponent();
            this.SetStyle(ControlStyles.SupportsTransparentBackColor, true);
        }

        public bool trans = false;
        public Bitmap oldbitmap = new Bitmap(1, 1);

        double oldPercentage = -1;
        string oldText = "";
        bool enter = false, scm = false;
        byte oldopacity = 255;
        bool insizearea = false;
        int[] linearmode = new int[] { 90, 0, 45, 135 };

        Bitmap backTextCache = new Bitmap(1, 1);
        Bitmap foreTextCache = new Bitmap(1, 1);

        protected override void WndProc(ref Message m)
        {
            switch (m.Msg)
            {
                case 0x0084:
                    base.WndProc(ref m);
                    Point vPoint = new Point((int)m.LParam & 0xFFFF, (int)m.LParam >> 16 & 0xFFFF);
                    vPoint = PointToClient(vPoint);
                    if (vPoint.X <= 5)
                    {
                        m.Result = (IntPtr)HT.LEFT;
                        insizearea = true;
                        SetBitmap(oldbitmap, oldopacity);
                    }
                    else if (vPoint.X >= ClientSize.Width - 5)
                    {
                        m.Result = (IntPtr)HT.RIGHT;
                        insizearea = true;
                        SetBitmap(oldbitmap, oldopacity);
                    }
                    else insizearea = false;
                    break;
                case 0x0201:
                    m.Msg = 0x00A1;
                    m.LParam = IntPtr.Zero;
                    m.WParam = new IntPtr(2);
                    base.WndProc(ref m);
                    break;
                default:
                    base.WndProc(ref m);
                    break;
            }
        }

        public void ClearCache()
        {
            oldPercentage = -1;
            oldText = "";
        }

        public void DrawText(string text)
        {
            if (text == oldText) return;
            if (text == "")
            {
                backTextCache = new Bitmap(1, 1);
                foreTextCache = new Bitmap(1, 1);
            }
            else
            {
                Size s = this.CreateGraphics().MeasureString(text, this.Font).ToSize();
                backTextCache = new Bitmap(s.Width, s.Height);
                foreTextCache = new Bitmap(s.Width, s.Height);
                Graphics gB = Graphics.FromImage(backTextCache);
                Graphics gF = Graphics.FromImage(foreTextCache);

                int lineMode = linearmode[LyricShowSetting.DLinearMode];
                gB.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAlias;
                gB.SmoothingMode = SmoothingMode.AntiAlias;
                gB.DrawString(text, this.Font, new SolidBrush(Color.FromArgb(128, 0, 0, 0)), new PointF(1, 1));
                gB.DrawString(text, this.Font, new LinearGradientBrush(new Rectangle(new Point(0, 0), backTextCache.Size), LyricShowSetting.DTextColor, LyricShowSetting.DTextColor1, lineMode), new PointF(0, 0));

                gF.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAlias;
                gF.SmoothingMode = SmoothingMode.AntiAlias;
                gF.DrawString(text, this.Font, new SolidBrush(Color.FromArgb(128, 0, 0, 0)), new PointF(1, 1));
                gF.DrawString(text, this.Font, new LinearGradientBrush(new Rectangle(new Point(0, 0), foreTextCache.Size), LyricShowSetting.DHTextColor, LyricShowSetting.DHTextColor1, lineMode), new PointF(0, 0));

                gB.Dispose();
                gF.Dispose();
            }
            oldText = text;
        }

        public void DrawToVisual(double percentage, byte opacity)
        {
            if (percentage == oldPercentage) return;
            
            Bitmap b = new Bitmap(this.Width, this.Height);
            Graphics g = Graphics.FromImage(b);
            Point offset = new Point(this.Width / 2 - backTextCache.Width / 2, 0);
            g.CompositingMode = CompositingMode.SourceCopy;

            if (backTextCache.Width > this.Width)
            {
                int highlightWidth = (int)(percentage * backTextCache.Width); 
                offset.X = 0;
                if(highlightWidth >= this.Width / 2)
                    offset.X = -(int)(highlightWidth - this.Width / 2);
                if (offset.X + backTextCache.Width < this.Width + 5) offset.X = this.Width - backTextCache.Width + 5;
            }

            if (LyricShowSetting.DKalaOK)
            {
                int foreOffset = (int)(foreTextCache.Width * percentage);
                if (foreOffset < 0) foreOffset = 0;

                g.DrawImage(backTextCache, offset);
                g.DrawImage(foreTextCache, new Rectangle(offset.X, 0, foreOffset, foreTextCache.Height), new Rectangle(0, 0, foreOffset, foreTextCache.Height), GraphicsUnit.Pixel);
            } else g.DrawImage(foreTextCache, offset);

            SetBitmap(b, opacity);
            g.Dispose();
            oldPercentage = percentage;
        }

        public void ResetLocation()
        {
            OnLocationChanged(null);
        }

        protected override void OnLocationChanged(EventArgs e)
        {
            if (this.Top > Screen.PrimaryScreen.WorkingArea.Bottom - this.Height) this.Top = Screen.PrimaryScreen.WorkingArea.Bottom - this.Height;
            if (this.Top < Screen.PrimaryScreen.WorkingArea.Top) this.Top = Screen.PrimaryScreen.WorkingArea.Top;
            base.OnLocationChanged(e);
        }

        private void CanPenetrate()
        {
            NativeMethods.GetWindowLong(this.Handle, (int)GWL.EXSTYLE);
            NativeMethods.SetWindowLong(this.Handle, (int)GWL.EXSTYLE, (int)(WS_EX.TRANSPARENT | WS_EX.LAYERED));
            trans = true;
        }

        private void CancelPenetrate()
        {
            NativeMethods.SetWindowLong(this.Handle, (int)GWL.EXSTYLE, (int)WS_EX.LAYERED);
            trans = false;
            scm = false;
        }

        public void Penetrate()
        {
            if (trans) CancelPenetrate();
            else CanPenetrate();
        }

        public override void SetBitmap(Bitmap bitmap, byte opacity)
        {
            oldbitmap = bitmap;
            oldopacity = opacity;
            Bitmap b = new Bitmap(this.Width, this.Height);
            Graphics g = Graphics.FromImage(b);
            if (scm || enter || insizearea)
            {
                GraphicsPath roundedRect = Core.Helper.CreateRoundedRectangle(new Rectangle(0, 0, this.Width - 1, this.Height - 1), 5);
                Pen p = new Pen(Color.FromArgb(128, LyricShowSetting.DBorderColor));
                SolidBrush sb = new SolidBrush(Color.FromArgb(128, LyricShowSetting.DBackColor));
                g.SmoothingMode = SmoothingMode.AntiAlias;
                g.FillPath(sb, roundedRect);
                g.DrawPath(p, roundedRect);
                g.DrawImage(bitmap, 0, 0);

                roundedRect.Dispose();
                p.Dispose();
                sb.Dispose();
            }
            else
            {
                g.FillRectangle(new SolidBrush(Color.FromArgb(1, 255, 255, 255)), new Rectangle(0, 0, this.Width, this.Height));
                g.DrawImage(bitmap, 0, 0);
            }
            bitmap = new Bitmap(b);
            g.Dispose();
            b.Dispose();
            base.SetBitmap(bitmap, opacity);
        }

        private void frmDesktopLyric_MouseDown(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left)
            {
                this.Capture = false;
                Message msg = Message.Create(Handle, (int)WM.NCLBUTTONDOWN, (IntPtr)HT.CAPTION, IntPtr.Zero);
                WndProc(ref msg);
            }
            else scm = true;
        }

        private void frmDesktopLyric_MouseEnter(object sender, EventArgs e)
        {
            enter = true;
            SetBitmap(oldbitmap, oldopacity);
        }

        private void frmDesktopLyric_MouseLeave(object sender, EventArgs e)
        {
            enter = false;
            SetBitmap(oldbitmap, oldopacity);
        }

        protected override void OnContextMenuChanged(EventArgs e)
        {
            base.OnContextMenuChanged(e);
            if (this.ContextMenu != null)
            {
                this.ContextMenu.Collapse += new EventHandler(ContextMenu_Collapse);
            }
        }

        private void ContextMenu_Collapse(object sender, EventArgs e)
        {
            scm = false;
            SetBitmap(oldbitmap, oldopacity);
        }

        protected override void OnSizeChanged(EventArgs e)
        {
            base.OnSizeChanged(e);
            if (this.Height != this.Font.Height) this.Height = this.Font.Height;
        }

        private void timer1_Tick(object sender, EventArgs e)
        {
            if (!this.Bounds.Contains(Control.MousePosition) && (insizearea || enter))
            {
                insizearea = false;
                enter = false;
                SetBitmap(oldbitmap, oldopacity);
            }
        }

        protected override CreateParams CreateParams
        {
            get
            {
                CreateParams cp = base.CreateParams;
                cp.ExStyle |= 0x00000080;
                return cp;
            }
        }
    }
}
